package com.googlecode.mvcguice.routing;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;

public final class UrlGenerator {
	private final UrlPattern urlPattern;
	private final List<ParameterBinder> parameterBinders;

	public UrlGenerator(UrlPattern urlPattern, List<ParameterBinder> parameterBinders) {
		this.urlPattern = urlPattern;
		this.parameterBinders = parameterBinders;
	}

	private static final Joiner.MapJoiner PARAMS_JOINER = Joiner.on('&').withKeyValueSeparator("=");

	public String generate(Object[] args) {
		final Map<String, String> parameters = getParameters(args);
		final String pathInfo = urlPattern.createUrl(parameters);

		// Remove variables and leave only params
		parameters.keySet().removeAll(urlPattern.getVariables());
		if (parameters.isEmpty()) {
			return pathInfo;
		} else {
			return PARAMS_JOINER.appendTo(new StringBuilder(pathInfo).append('?'), parameters).toString();
		}
	}

	private Map<String, String> getParameters(Object[] args) {
		Preconditions.checkArgument(args.length == parameterBinders.size(),
				"Expected: %s args, actual: %s", parameterBinders.size(), args.length);

		final int n = args.length;
		final Map<String, String> parameters = new HashMap<String, String>(n);
		for (int i = 0; i < n; i++) {
			final ParameterBinder binder = parameterBinders.get(i);
			final String paramName = binder.getName();
			if (paramName != null) {
				final Object arg = args[i];
				final String paramValue = arg == null ? null : arg.toString();
				parameters.put(paramName, paramValue);
			}
		}

		return parameters;
	}
}
